//给定一个非负整数 n ，请计算 0 到 n 之间的每个数字的二进制表示中 1 的个数，并输出一个数组。
//
//
//
// 示例 1:
//
//
//输入: n = 2
//输出: [0,1,1]
//解释:
//0 --> 0
//1 --> 1
//2 --> 10
//
//
// 示例 2:
//
//
//输入: n = 5
//输出: [0,1,1,2,1,2]
//解释:
//0 --> 0
//1 --> 1
//2 --> 10
//3 --> 11
//4 --> 100
//5 --> 101
//
//
//
//
// 说明 :
//
//
// 0 <= n <= 10⁵
//
//
//
//
// 进阶:
//
//
// 给出时间复杂度为 O(n*sizeof(integer)) 的解答非常容易。但你可以在线性时间 O(n) 内用一趟扫描做到吗？
// 要求算法的空间复杂度为 O(n) 。
// 你能进一步完善解法吗？要求在C++或任何其他语言中不使用任何内置函数（如 C++ 中的 __builtin_popcount ）来执行此操作。
//
//
//
//
//
// 注意：本题与主站 338 题相同：https://leetcode-cn.com/problems/counting-bits/
//
// Related Topics 位运算 动态规划 👍 134 👎 0

function countBits(n: number): number[] {

    /**
     * @param {number} n
     * @return {number[]}
     */
    let res = new Array(n + 1).fill(0);
    for (let i = 0; i <= n; i++) {
        let j = i;
        while (j != 0) {
            //? 利用 i & (i-1) 能将整数i的二进制形式最右边的1变为0
            //? &按位与 j 的最后一位1 j-1时必然变成0 通过按位与可以将此位变为0 当全为0时j自然成了0
            j = j & (j - 1);
            res[i]++;
        }
    }
    return res;


};

function countBits2(n: number): number[] {

    /**
     * @param {number} n
     * @return {number[]}
     */
    let res = new Array(n + 1).fill(0);
    //? 动态规划
    //? i & (i-1) 能将整数i的二进制形式最右边的1变为0，那么 整数i的二进制中1的个数比整数i&(i-1)的二进制中1的个数多1.
    for (let i = 1; i <= n; i++) {
        res[i] = res[i & (i - 1)] + 1;
    }
    return res;

};

function countBits3(n: number): number[] {

    /**
     * @param {number} n
     * @return {number[]}
     */
    /*
    ? 如果正整数i是一个偶数，那么i相当于将i/2左移一位的结果，也就是说偶数i和i/2的二进制形式中的1的个数是相同的
    ? 如果i是奇数，则i相当于将i/2左移一位之后再将最右边一位设为1的结果，因此奇数i的二进制形式中1的个数比i/2的1的个数多1
     */
    let res = new Array(n + 1).fill(0);
    for (let i = 1; i <= n; i++) {
        //? i & 1 这种技巧可以用来判断一个数是奇数还是偶数，因为奇数的二进制表示的最后一位是 1，偶数的二进制表示的最后一位是 0
        res[i] = res[i >> 1] + (i & 1);
    }
    return res;
};

